package td.game;

import java.util.Vector;

import util.Util;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.text.TextPaint;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import comm.CommunicationHandler;

import entities.BkgMap;
import entities.MapPanel;
import entities.Turret;
import entities.TurretPoint;

public class MainGamePanel extends SurfaceView implements SurfaceHolder.Callback {
	//Tag to identify this class in the logger
	private final String TAG = MainGamePanel.class.getSimpleName();
	
	public static final int MESSAGE_ARRIVED = 0;
	public static final int ERROR_MESSAGE_ARRIVED = 1;
	
	//The rect area where the bmp must not leave
	public static final Rect BKG_MAP_RECT = new Rect((int)Math.round(Main.SCREEN_WIDTH*0.3), 0, Main.SCREEN_WIDTH, Main.SCREEN_HEIGHT);
	public static final Rect MAP_PANEL_RECT = new Rect(0, 0, (int)Math.round(Main.SCREEN_WIDTH*0.3), Main.SCREEN_HEIGHT);
	
	//How many tiles are in the phase map
	public static final int TILES_IN_X = 10;
	public static final int TILES_IN_Y = 10;
	
	//Defines the msg.what int (inside messages)
	public static final int TURRET_POINT = -1;
	public static final int TURRET1 = 1;
	public static final int TURRET2 = 2;
	
	private int gameState;
	private Bitmap gameFinishedPanel;
	private final int GAME_WON = 1;
	private final int GAME_LOST = 2;
	
	private MainThread thread; //The main thread that runs the game
	private BkgMap bkgMap; //The background map
	private MapPanel mapPanel;
	
	private static int player;
	
	private CommunicationHandler communicationHandler;
	
	private Handler errorHandler;
	
	public static float density;

	public MainGamePanel(Context context, Handler errorHandler) {
		super(context);
		// adding the callback (this) to the surface holder to intercept events
		getHolder().addCallback(this);
		
		this.errorHandler = errorHandler;

		player = 0;
		
		gameState = 0;
		
		density = getResources().getDisplayMetrics().density;
		
		Util.populateTurrets();
		
		bkgMap = new BkgMap(BitmapFactory.decodeResource(getResources(), R.drawable.fase1), 
				new Point(BKG_MAP_RECT.left, BKG_MAP_RECT.top),
				BitmapFactory.decodeResource(getResources(), R.drawable.metralhadora_lvl1),
				BitmapFactory.decodeResource(getResources(), R.drawable.metralhadora_lvl2),
				BitmapFactory.decodeResource(getResources(), R.drawable.metralhadora_lvl3),
				BitmapFactory.decodeResource(getResources(), R.drawable.canhao_lvl1),
				BitmapFactory.decodeResource(getResources(), R.drawable.canhao_lvl2),
				BitmapFactory.decodeResource(getResources(), R.drawable.canhao_lvl3),
				BitmapFactory.decodeResource(getResources(), R.drawable.turretpoint),
				insideHandler);
		mapPanel = new MapPanel(BitmapFactory.decodeResource(getResources(), R.drawable.map_panel), 
				new Point(MAP_PANEL_RECT.left, MAP_PANEL_RECT.top), 
				BitmapFactory.decodeResource(getResources(), R.drawable.btn_bkg),
				BitmapFactory.decodeResource(getResources(), R.drawable.caixa),
				BitmapFactory.decodeResource(getResources(), R.drawable.separador));

		thread = new MainThread(getHolder(), this);

		communicationHandler = new CommunicationHandler(outsideHandler);
		if(communicationHandler.isNull()){
			errorHandler.obtainMessage(MainGamePanel.ERROR_MESSAGE_ARRIVED, Main.KILL_APP, -1, "Couldn't connect to Framework.").sendToTarget();
		}
		player = 0;
		
		// make the GamePanel focusable so it can handle events
		setFocusable(true);
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		Log.i(TAG, "Surface changed.");
		
	}

	public void surfaceCreated(SurfaceHolder holder) {
		thread.setRunning(true);
		thread.start();
		Log.i(TAG, "Surface created.");
	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		boolean retry = true;
		while (retry) {
			try {
				thread.join();
				retry = false;
			} catch (InterruptedException e) {
				// try again shutting down the thread
			}
		}
		Log.i(TAG, "Surface destroyed.");
		
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		//The screen stays black until the game is connected with the display or the game's not in running state
		if(player == 0){ 
			return false;
		}
		
		if ((gameState == GAME_LOST) || (gameState == GAME_WON)) {
			Main.lala();
		}
		//Delegates the event handling to the entities
		int action = mapPanel.handleActionDown(event); //delegating event handling to the map panel
		
		TurretPoint tp;
		Turret turret;
		switch (action){
			case MapPanel.CREATE_BUTTON_1_CLICKED:
				tp = bkgMap.getSelectedTP();
				Log.i(TAG, "Tile do TP selecionado: "+tp.getTile().x+", "+tp.getTile().y);
				
				communicationHandler.createTurret(tp, Util.TURRET1);
			break;

			case MapPanel.CREATE_BUTTON_2_CLICKED:
				tp = bkgMap.getSelectedTP();
				
				communicationHandler.createTurret(tp, Util.TURRET2);
			break;
			
			case MapPanel.SELL_BUTTON_CLICKED:
				turret = bkgMap.getselectedTurret();
				
				communicationHandler.sellTurret(turret);
			break;
			
			case MapPanel.UPGRADE_BUTTON_CLICKED:
				turret = bkgMap.getselectedTurret();
				
				communicationHandler.upgradeTurret(turret);
			break;
		}
		
		if (!mapPanel.isTouched()){
			//The bckgd map only moves if the panel doesn't move. It keeps the bkgd from moving when touch the panel
			bkgMap.handleActionDown(event); //delegating event handling to the background map
		}
		
		return true;
	}
	
	
	
	@Override
	protected void onDraw(Canvas canvas) {
		if(player == 0){ //The screen stays black until the game is connected with the display
			TextPaint waitPaint = new TextPaint();
			waitPaint.setColor(Color.WHITE);
			//textPaint.setTextSize(MainGamePanel.density * 25f);
			waitPaint.setTextSize(MainGamePanel.density * 30f);
			//waitPaint.setTextSize(45);
			
			waitPaint.setTypeface(Main.getFont());
			
			int y = Main.SCREEN_HEIGHT/2 - 30;
			String waitString = new String();
			waitString = "Connecting to the display..."; 
			canvas.drawText(waitString, Main.SCREEN_WIDTH/2 - waitPaint.measureText(waitString)/2, y, waitPaint);
			
			return;
		}
		
		if(gameState == GAME_LOST){
			
			gameFinishedPanel = Util.resizeBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.perdeu_jogo),
					Main.SCREEN_WIDTH-200, 100);
			canvas.drawColor(Color.BLACK);
			canvas.drawBitmap(gameFinishedPanel, Main.SCREEN_WIDTH/2-gameFinishedPanel.getWidth()/2, Main.SCREEN_HEIGHT/2-50, null);
			
		} else if (gameState == GAME_WON){
			
			gameFinishedPanel = Util.resizeBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ganhou_jogo),
					Main.SCREEN_WIDTH-100, 100);
			canvas.drawColor(Color.BLACK);
			canvas.drawBitmap(gameFinishedPanel, Main.SCREEN_WIDTH/2-gameFinishedPanel.getWidth()/2, Main.SCREEN_HEIGHT/2-50, null);
			
		} else {
			canvas.drawColor(Color.BLUE);
			bkgMap.draw(canvas);
			mapPanel.draw(canvas);
		}
	}
	
	public static int getPlayer(){
		return player;
	}
	
	//This handler handles the messages sent from the turret (points) when they are clicked
	public final Handler insideHandler = new Handler() {
        @Override
        public void handleMessage(Message msg){
        	switch (msg.what) {
            case TURRET1: //A turret was clicked
            	Turret turret = (Turret) msg.obj;
                mapPanel.updateInfo(turret);
                
            break;
            case TURRET_POINT: //A turret point was clicked
            	TurretPoint tp = (TurretPoint) msg.obj;
                mapPanel.updateInfo(tp);
            break;
        	}
        }
	};
	
	//This handler handles the messages coming from the framework, redirected by the Connection Handler 
	public final Handler outsideHandler = new Handler(){
		@Override
		public void handleMessage(Message message){
			Log.i(TAG, "outside handler.");
			if(message.what == ERROR_MESSAGE_ARRIVED){
				errorHandler.obtainMessage(message.what, message.arg1, message.arg2, message.obj).sendToTarget();
				
			} else if (message.what == MESSAGE_ARRIVED){
				if(message.arg1 <=0){
					return;
				}
			
				comm.Message msg = new comm.Message();
				msg.decode(new String((byte[])message.obj, 0, message.arg1));
				
				
				switch (msg.getType()){ 
					case Util.ERROR:
						mapPanel.setShowingError(true);
					break;
					
					case Util.ENTITY_UPDATE:
						switch (msg.getAction()){
							case Util.CREATE:
								//Erase the turret point and create a turret

								bkgMap.createTurret(new Point(msg.getTileX(), msg.getTileY()), msg.getTurret());
								mapPanel.updateInfo();
							break;
							case Util.SELL:
								//Erase the turret and create a turret point
								Log.i(TAG, "Vendeu do tile: "+ msg.getTileX()+ ", "+msg.getTileY());
								bkgMap.sellTurret(new Point(msg.getTileX(), msg.getTileY()));
								mapPanel.updateInfo();
							break;
							case Util.UPGRADE:
								bkgMap.upgradeTurret(new Point(msg.getTileX(), msg.getTileY()));
								mapPanel.updateInfo();
							break;
						}
					break;
					case Util.ENTITY_REDEFINITION:					
						
						Vector<Point> newPoints = msg.getPt();
						Vector<Integer> newPlayers = msg.getPlayers();
						Vector<Integer> newEntityType = msg.getEntityType();
						Vector<Integer> newEntityLevel = msg.getEntityLevel();
						Vector<TurretPoint> tps = bkgMap.getTurretPoints();
						Vector<Turret> turrets = bkgMap.getTurrets();
						
						player = msg.getPlayerNumber();
						
						mapPanel.updateInfo();
						
						int i;
						int j;
						
						

						for(; turrets.size()>0;){
							bkgMap.sellTurret(new Point(turrets.elementAt(0).getTile().x, turrets.elementAt(0).getTile().y));
						}
						
						
						for (i = 0; i < newPoints.size(); i++){
							if (newEntityType.elementAt(i) == TURRET_POINT){
								for (j=0; j<tps.size(); j++){
									if (tps.elementAt(j).getTile().equals(newPoints.elementAt(i))){
										tps.elementAt(j).setPlayer(newPlayers.elementAt(i));
									}
								}
							
							} else {
								bkgMap.createTurret(newPoints.elementAt(i), newEntityType.elementAt(i));
								turrets.lastElement().setPlayer(newPlayers.elementAt(i));
								for(int q = newEntityLevel.elementAt(i)-1; q > 0; q--){
									bkgMap.upgradeTurret(newPoints.elementAt(i));
								}
							}
						}
						
					break;
					case Util.GAME_STATE:
						switch(msg.getAction()){
						case Util.WIN:
							gameState = GAME_WON;
							break;
						case Util.LOSE:
							gameState = GAME_LOST;
							break;
						}
					break;
				}
			}
		}
	};
}
